/*
 * (C) Copyright 2013 - Thales SA (author: Simon DENEL - Thales Research & Technology)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
*/
#ifndef LIB_LTPV_COMMON_H
	#define LIB_LTPV_COMMON_H

	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/time.h>
	#include <stdint.h>
	#include <time.h>

	#define LTPV_DEBUG 1
	
	struct ltpv_t_device;
	struct ltpv_t_stream;
	
	struct ltpv_t_taskInstance {
		unsigned long idTask;
		char name[500];
		char* details;
		uint64_t start;
		uint64_t end;
		uint64_t ocl_queued;
		uint64_t ocl_submit;
		uint64_t ocl_size; /* must contain the data size transferred during the task, otherwise 0 */
		uint64_t ocl_bandwidth; /* bytes/s */
		uint64_t ltpv_time_start_CPU; // Used for accelerators in synchronized mode
		struct ltpv_t_taskInstance *next;
	};
	typedef struct ltpv_t_taskInstance ltpv_t_taskInstance;

	struct ltpv_t_task {
		unsigned long id;
		char name[500];
		struct ltpv_t_task *next;
	};
	typedef struct ltpv_t_task ltpv_t_task;

	struct ltpv_t_stream {
		int id;
		char name[500];
		ltpv_t_taskInstance *firstTaskInstance;
		ltpv_t_device* device;
		struct ltpv_t_stream *next;
	};
	typedef struct ltpv_t_stream ltpv_t_stream;

	struct ltpv_t_device {
		int id;
		char name[500];
		char *details;
		unsigned long timeOffset;
		uint64_t ltpv_time_offset1_CPU; // Can be use to calibrate different time counter (a device one among the CPU, reference one)
		uint64_t ltpv_time_offset1_DEV;
		uint64_t ltpv_time_offset2_CPU;
		uint64_t ltpv_time_offset2_DEV;
		uint64_t ltpv_OpenCL_device; // cl_device_id device, only used with OpenCL
		ltpv_t_stream *firstStream;
		struct ltpv_t_device *next;
	};
	typedef struct ltpv_t_device ltpv_t_device;

	struct ltpv_t_end_functions {
		void (*function)();
		struct ltpv_t_end_functions *next;
	};
	typedef struct ltpv_t_end_functions ltpv_t_end_functions;

	void ltpv_start();

	ltpv_t_device *ltpv_addDevice(
		int idDevice,
		const void *nameDevice,
		void *detailsDevice=NULL,
		long timeOffset=0
	);

	void ltpv_addStream(
		int idStream,
		int idDevice,
		const void *name
	);

	void ltpv_addTask(
		unsigned long idTask,
		const void *nameTask
	);

	ltpv_t_taskInstance *ltpv_addTaskInstance(
		unsigned long idTask,
		const char* name,
		char* details,
		int idStream,
		uint64_t start,
		uint64_t end,
		uint64_t ocl_queue     = 0LL,
		uint64_t ocl_submit    = 0LL,
		long ocl_size      = 0,
		long ocl_bandwidth = 0
	);

	void ltpv_stopAndRecord(
		const void *filename
	);
	#if __WORDSIZE == 64  
	#define __PRI64_PREFIX    "l"  
	#define __PRIPTR_PREFIX   "l"  
	#else  
	#define __PRI64_PREFIX    "ll"  
	#define __PRIPTR_PREFIX  
	#endif  
	#define PRId64     __PRI64_PREFIX "d"  
#endif
